題目連結(https://leetcode.com/problems/jump-game/description/)
You are given an integer array nums where each element nums[i] indicates your maximum jump length at that position.
Return true if you can reach the last index starting from index 0, or false otherwise.
今天分享的這題我一開始想到的是 DP,但其實用 greedy 解比較快,所以來分享一下兩種方法的程式碼與比較
nums 每個數字代表從當前位置可跳的最大長度true 如果從 index 0 開始可達最終索引,不行則回傳 false
1 <= nums.length <= 10^4
0 <= nums[i] <= 10^5
Input: nums = [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.
Input: nums = [3,2,1,0,4]
Output: false
Explanation: 不管從 0,1,2 開始跳都會經過 3, 但 3 沒有跳躍步長
class Solution {
public:
bool canJump(vector<int>& nums) {
int n = nums.size() - 1;
vector<bool> dp(n+1, false); //至少要有1個空間,不然[0]的測資會錯誤
dp[0] = true;
for(int i = 0; i < n; i++){
if(!dp[i]) continue; // 如果當前位置不能到達,跳過
for(int j = 1; j <= nums[i] && i+j <= n; j++){
//從位置 i 跳 j 步到 i+j
dp[i+j] = true; //從 i+1 到 n 設成可達(在 nums[i] 還沒用完之前)
}
}
return dp[n];
}
};
class Solution {
public:
bool canJump(vector<int>& nums) {
int n = nums.size() - 1;
int maxreach = 0;
for(int i = 0; i <= n; i++){
if(i > maxreach) return false; // 如果當前位置超過了能到達的最遠位置,返回 false
maxreach = max(maxreach, i + nums[i]);// 更新能到達的最遠位置
}
return true;
}
};
// 時間: O(n), 空間: O(1)
bool canJump_Backward(vector<int>& nums) {
int n = nums.size() - 1;
int lastPos = n; // 目標位置
// 從倒數第二個位置開始往前檢查
for (int i = n - 1; i >= 0; i--) {
// 如果從位置 i 能跳到目標位置
if (i + nums[i] >= lastPos) {
lastPos = i; // 更新目標位置
}
}
return lastPos == 0;
}
範例: nums = [3, 2, 1, 0, 4]
索引: 0 1 2 3 4
視覺化過程:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
起點: 0
↓
dp = [T, F, F, F, F]
從 i=0 (可達) 跳躍:
↓ ↓ ↓
dp = [T, T, T, T, F]
從 i=1 (可達) 跳躍:
↓ ↓
dp = [T, T, T, T, F]
從 i=2 (可達) 跳躍:
↓
dp = [T, T, T, T, F]
i=3 (可達): nums[3]=0,跳不到任何地方
dp = [T, T, T, T, F]
i=4 (不可達): ❌ 跳過!
因為 dp[4]=F
我們根本沒有到達 i=4
所以不需要考慮從 i=4 能跳去哪
範例: [2, 3, 1, 1, 4]
n = 4
i=0: maxreach=2, 2>=4? No, 繼續
i=1: maxreach=4, 4>=4? Yes → return true ✓
↑
在這裡就返回了!
nums = [3, 2, 1, 0, 4]
索引: 0 1 2 3 4
反向檢查:
i=3: 3+0=3 < 4 ✗ 跳不到,lastPos 還是 4
i=2: 2+1=3 < 4 ✗ 跳不到,lastPos 還是 4
i=1: 1+2=3 < 4 ✗ 跳不到,lastPos 還是 4
i=0: 0+3=3 < 4 ✗ 跳不到,lastPos 還是 4
最終 lastPos = 4 ≠ 0
結論: 無法從 0 到達 4 ✓ 正確!
continue?if dp[i] == false:
代表: 從起點無法到達位置 i
推論: 我們永遠不會站在位置 i
結論: 討論「從位置 i 能跳去哪」毫無意義
行動: 直接跳過 (continue)
實際執行流程
i=0: dp[0]=true ✓ 執行內層迴圈,標記可達位置
i=1: dp[1]=true ✓ 執行內層迴圈,標記可達位置
i=2: dp[2]=false ✗ continue,跳過內層迴圈
i=3: dp[3]=false ✗ continue,跳過內層迴圈
i=4: dp[4]=true ✓ 執行內層迴圈,標記可達位置
正確性分析
for(int i = 0; i < n; i++){
if(!dp[i]) continue; *// ✓ 避免做不避免運算,不是必須*
for(int j = 1; j <= nums[i] && i+j <= n; j++){
dp[i+j] = true;
}
}
由前往後
maxreach = max(maxreach, i + nums[i]);// 更新能到達的最遠位置
由後往前
原問題: 能否從 0 到達 n?
如果從 i 能跳到 n:
新問題: 能否從 0 到達 i?
如果從 j 能跳到 i:
新問題: 能否從 0 到達 j?
... 持續簡化 ...
如果最終簡化到: 能否從 0 到達 0?
答案: YES!因為已經在起點了
ps. 部分內容經 AI 協助整理